package cn.iocoder.yudao.module.system.service.ranking;

import cn.iocoder.yudao.module.system.dal.dataobject.examscore.ExamScoreDO;
import cn.iocoder.yudao.module.system.dal.dataobject.subjectscoredetail.SubjectScoreDetailDO;
import cn.iocoder.yudao.module.system.dal.mysql.examscore.ExamScoreMapper;
import cn.iocoder.yudao.module.system.dal.mysql.subjectscoredetail.SubjectScoreDetailMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 排名计算 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class RankingCalculationServiceImpl implements RankingCalculationService {

    @Resource
    private ExamScoreMapper examScoreMapper;
    
    @Resource
    private SubjectScoreDetailMapper subjectScoreDetailMapper;

    @Override
    @Transactional
    public void calculateAllRankings(Long examId) {
        // 1. 计算总分排名
        calculateSchoolTotalRanking(examId);
        calculateClassTotalRanking(examId);
        
        // 2. 计算选科组合排名
        calculateCombinationRanking(examId);
        
        // 3. 计算所有科目排名
        calculateAllSubjectRankings(examId);
    }

    @Override
    @Transactional
    public void calculateSchoolTotalRanking(Long examId) {
        // 获取所有学生成绩，按总分降序排列
        List<ExamScoreDO> scores = examScoreMapper.selectListByExamId(examId);
        
        // 按赋分后的总分排序（如果有赋分），否则按原始总分排序
        // 处理缺考情况：null 值排在最后
        scores.sort((a, b) -> {
            BigDecimal scoreA = a.getTotalScoreAssigned() != null ? a.getTotalScoreAssigned() : a.getTotalScore();
            BigDecimal scoreB = b.getTotalScoreAssigned() != null ? b.getTotalScoreAssigned() : b.getTotalScore();
            // 处理 null 值：null 排在最后
            if (scoreA == null && scoreB == null) return 0;
            if (scoreA == null) return 1;  // a 是 null，排在后面
            if (scoreB == null) return -1; // b 是 null，排在后面
            return scoreB.compareTo(scoreA); // 降序
        });
        
        // 计算排名（处理并列情况）
        int currentRank = 1;
        BigDecimal lastScore = null;
        int sameScoreCount = 0;
        
        for (int i = 0; i < scores.size(); i++) {
            ExamScoreDO score = scores.get(i);
            BigDecimal currentScore = score.getTotalScoreAssigned() != null ? 
                score.getTotalScoreAssigned() : score.getTotalScore();
            
            // 如果分数为 null（缺考），不参与排名
            if (currentScore == null) {
                score.setSchoolRank(null);
                examScoreMapper.updateById(score);
                continue;
            }
            
            if (lastScore == null || currentScore.compareTo(lastScore) != 0) {
                currentRank = i + 1;
                sameScoreCount = 1;
            } else {
                sameScoreCount++;
            }
            
            // 更新校内排名
            score.setSchoolRank(currentRank);
            examScoreMapper.updateById(score);
            
            lastScore = currentScore;
        }
    }

    @Override
    @Transactional
    public void calculateClassTotalRanking(Long examId) {
        // 按班级分组计算排名
        List<ExamScoreDO> allScores = examScoreMapper.selectListByExamId(examId);
        Map<String, List<ExamScoreDO>> scoresByClass = allScores.stream()
            .collect(Collectors.groupingBy(ExamScoreDO::getClassName));
        
        for (Map.Entry<String, List<ExamScoreDO>> entry : scoresByClass.entrySet()) {
            List<ExamScoreDO> classScores = entry.getValue();
            
            // 按总分降序排列，处理缺考情况：null 值排在最后
            classScores.sort((a, b) -> {
                BigDecimal scoreA = a.getTotalScoreAssigned() != null ? a.getTotalScoreAssigned() : a.getTotalScore();
                BigDecimal scoreB = b.getTotalScoreAssigned() != null ? b.getTotalScoreAssigned() : b.getTotalScore();
                // 处理 null 值：null 排在最后
                if (scoreA == null && scoreB == null) return 0;
                if (scoreA == null) return 1;  // a 是 null，排在后面
                if (scoreB == null) return -1; // b 是 null，排在后面
                return scoreB.compareTo(scoreA);
            });
            
            // 计算班级排名
            int currentRank = 1;
            BigDecimal lastScore = null;
            
            for (int i = 0; i < classScores.size(); i++) {
                ExamScoreDO score = classScores.get(i);
                BigDecimal currentScore = score.getTotalScoreAssigned() != null ? 
                    score.getTotalScoreAssigned() : score.getTotalScore();
                
                // 如果分数为 null（缺考），不参与排名
                if (currentScore == null) {
                    score.setClassRank(null);
                    examScoreMapper.updateById(score);
                    continue;
                }
                
                if (lastScore == null || currentScore.compareTo(lastScore) != 0) {
                    currentRank = i + 1;
                }
                
                // 更新班级排名
                score.setClassRank(currentRank);
                examScoreMapper.updateById(score);
                
                lastScore = currentScore;
            }
        }
    }

    @Override
    @Transactional
    public void calculateCombinationRanking(Long examId) {
        // 按选科组合分组计算排名
        List<ExamScoreDO> allScores = examScoreMapper.selectListByExamId(examId);
        Map<String, List<ExamScoreDO>> scoresByCombination = allScores.stream()
            .filter(score -> score.getSubjectCombination() != null)
            .collect(Collectors.groupingBy(ExamScoreDO::getSubjectCombination));
        
        for (Map.Entry<String, List<ExamScoreDO>> entry : scoresByCombination.entrySet()) {
            List<ExamScoreDO> combinationScores = entry.getValue();
            
            // 按总分降序排列，处理缺考情况：null 值排在最后
            combinationScores.sort((a, b) -> {
                BigDecimal scoreA = a.getTotalScoreAssigned() != null ? a.getTotalScoreAssigned() : a.getTotalScore();
                BigDecimal scoreB = b.getTotalScoreAssigned() != null ? b.getTotalScoreAssigned() : b.getTotalScore();
                // 处理 null 值：null 排在最后
                if (scoreA == null && scoreB == null) return 0;
                if (scoreA == null) return 1;  // a 是 null，排在后面
                if (scoreB == null) return -1; // b 是 null，排在后面
                return scoreB.compareTo(scoreA);
            });
            
            // 计算组合排名
            int currentRank = 1;
            BigDecimal lastScore = null;
            
            for (int i = 0; i < combinationScores.size(); i++) {
                ExamScoreDO score = combinationScores.get(i);
                BigDecimal currentScore = score.getTotalScoreAssigned() != null ? 
                    score.getTotalScoreAssigned() : score.getTotalScore();
                
                // 如果分数为 null（缺考），不参与排名
                if (currentScore == null) {
                    score.setCombinationRank(null);
                    examScoreMapper.updateById(score);
                    continue;
                }
                
                if (lastScore == null || currentScore.compareTo(lastScore) != 0) {
                    currentRank = i + 1;
                }
                
                // 更新组合排名
                score.setCombinationRank(currentRank);
                examScoreMapper.updateById(score);
                
                lastScore = currentScore;
            }
        }
    }

    @Override
    @Transactional
    public void calculateSubjectSchoolRanking(Long examId, String subjectName) {
        // 获取该科目的所有成绩
        List<SubjectScoreDetailDO> subjectScores = subjectScoreDetailMapper
            .selectByExamIdAndSubject(examId, subjectName);
        
        // 按原始分降序排列
        subjectScores.sort((a, b) -> {
            if (a.getOriginalScore() == null && b.getOriginalScore() == null) return 0;
            if (a.getOriginalScore() == null) return 1;
            if (b.getOriginalScore() == null) return -1;
            return b.getOriginalScore().compareTo(a.getOriginalScore());
        });
        
        // 计算校内排名
        int currentRank = 1;
        BigDecimal lastScore = null;
        
        for (int i = 0; i < subjectScores.size(); i++) {
            SubjectScoreDetailDO score = subjectScores.get(i);
            BigDecimal currentScore = score.getOriginalScore();
            
            if (currentScore != null) {
                if (lastScore == null || currentScore.compareTo(lastScore) != 0) {
                    currentRank = i + 1;
                }
                
                score.setSchoolRank(currentRank);
                lastScore = currentScore;
            } else {
                score.setSchoolRank(null); // 没有成绩的不参与排名
            }
            
            subjectScoreDetailMapper.updateById(score);
        }
    }

    @Override
    @Transactional
    public void calculateSubjectClassRanking(Long examId, String subjectName) {
        // 获取该科目的所有成绩
        List<SubjectScoreDetailDO> allSubjectScores = subjectScoreDetailMapper
            .selectByExamIdAndSubject(examId, subjectName);
        
        // 按班级分组
        Map<String, List<SubjectScoreDetailDO>> scoresByClass = allSubjectScores.stream()
            .filter(score -> score.getOriginalScore() != null)
            .collect(Collectors.groupingBy(score -> {
                // 通过学生ID获取班级信息
                ExamScoreDO examScore = examScoreMapper.selectByExamIdAndStudentId(examId, score.getStudentId());
                return examScore != null ? examScore.getClassName() : "未知班级";
            }));
        
        for (Map.Entry<String, List<SubjectScoreDetailDO>> entry : scoresByClass.entrySet()) {
            List<SubjectScoreDetailDO> classScores = entry.getValue();
            
            // 按原始分降序排列
            classScores.sort((a, b) -> b.getOriginalScore().compareTo(a.getOriginalScore()));
            
            // 计算班级排名
            int currentRank = 1;
            BigDecimal lastScore = null;
            
            for (int i = 0; i < classScores.size(); i++) {
                SubjectScoreDetailDO score = classScores.get(i);
                BigDecimal currentScore = score.getOriginalScore();
                
                if (lastScore == null || currentScore.compareTo(lastScore) != 0) {
                    currentRank = i + 1;
                }
                
                score.setClassRank(currentRank);
                subjectScoreDetailMapper.updateById(score);
                
                lastScore = currentScore;
            }
        }
    }

    @Override
    @Transactional
    public void calculateAllSubjectRankings(Long examId) {
        // 获取所有科目
        List<String> subjectList = subjectScoreDetailMapper.selectDistinctSubjectsByExamId(examId);
        Set<String> subjects = new HashSet<>(subjectList);
        
        for (String subject : subjects) {
            calculateSubjectSchoolRanking(examId, subject);
            calculateSubjectClassRanking(examId, subject);
        }
    }

    @Override
    public RankingStatistics getRankingStatistics(Long examId) {
        List<ExamScoreDO> allScores = examScoreMapper.selectListByExamId(examId);
        
        if (allScores.isEmpty()) {
            return new RankingStatistics(examId, 0, 0, new HashMap<>(), new HashMap<>(), null);
        }
        
        // 统计基本信息
        Integer totalStudents = allScores.size();
        Set<String> classes = allScores.stream()
            .map(ExamScoreDO::getClassName)
            .filter(Objects::nonNull)
            .collect(Collectors.toSet());
        Integer totalClasses = classes.size();
        
        // 统计选科组合
        Map<String, Integer> combinationCounts = allScores.stream()
            .filter(score -> score.getSubjectCombination() != null)
            .collect(Collectors.groupingBy(
                ExamScoreDO::getSubjectCombination,
                Collectors.collectingAndThen(Collectors.counting(), Math::toIntExact)
            ));
        
        // 统计总分范围
        List<BigDecimal> totalScores = allScores.stream()
            .map(score -> score.getTotalScoreAssigned() != null ? 
                score.getTotalScoreAssigned() : score.getTotalScore())
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
        
        RankingRange totalScoreRange = null;
        if (!totalScores.isEmpty()) {
            BigDecimal maxScore = totalScores.stream().max(BigDecimal::compareTo).orElse(BigDecimal.ZERO);
            BigDecimal minScore = totalScores.stream().min(BigDecimal::compareTo).orElse(BigDecimal.ZERO);
            BigDecimal avgScore = totalScores.stream()
                .reduce(BigDecimal.ZERO, BigDecimal::add)
                .divide(new BigDecimal(totalScores.size()), 2, RoundingMode.HALF_UP);
            totalScoreRange = new RankingRange(maxScore, minScore, avgScore, totalScores.size());
        }
        
        // 统计各科目排名范围
        Map<String, RankingRange> subjectRankingRanges = new HashMap<>();
        List<String> subjectList = subjectScoreDetailMapper.selectDistinctSubjectsByExamId(examId);
        Set<String> subjects = new HashSet<>(subjectList);
        
        for (String subject : subjects) {
            List<SubjectScoreDetailDO> subjectScores = subjectScoreDetailMapper
                .selectByExamIdAndSubject(examId, subject);
            
            List<BigDecimal> scores = subjectScores.stream()
                .map(SubjectScoreDetailDO::getOriginalScore)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
            
            if (!scores.isEmpty()) {
                BigDecimal maxScore = scores.stream().max(BigDecimal::compareTo).orElse(BigDecimal.ZERO);
                BigDecimal minScore = scores.stream().min(BigDecimal::compareTo).orElse(BigDecimal.ZERO);
                BigDecimal avgScore = scores.stream()
                    .reduce(BigDecimal.ZERO, BigDecimal::add)
                    .divide(new BigDecimal(scores.size()), 2, RoundingMode.HALF_UP);
                subjectRankingRanges.put(subject, new RankingRange(maxScore, minScore, avgScore, scores.size()));
            }
        }
        
        return new RankingStatistics(examId, totalStudents, totalClasses, 
            combinationCounts, subjectRankingRanges, totalScoreRange);
    }

    @Override
    public StudentRankingInfo getStudentRankingInfo(Long examId, Long studentId) {
        ExamScoreDO examScore = examScoreMapper.selectByExamIdAndStudentId(examId, studentId);
        if (examScore == null) {
            return null;
        }
        
        StudentRankingInfo info = new StudentRankingInfo();
        info.setStudentId(studentId);
        info.setStudentName(examScore.getStudentName());
        info.setStudentNo(examScore.getStudentNo());
        info.setClassName(examScore.getClassName());
        info.setSubjectCombination(examScore.getSubjectCombination());
        info.setTotalScore(examScore.getTotalScore());
        info.setTotalAssignedScore(examScore.getTotalScoreAssigned());
        info.setSchoolRank(examScore.getSchoolRank());
        info.setClassRank(examScore.getClassRank());
        info.setCombinationRank(examScore.getCombinationRank());
        
        // 获取各科目成绩
        List<SubjectScoreDetailDO> subjectScores = subjectScoreDetailMapper
            .selectByExamIdAndStudentId(examId, studentId);
        
        Map<String, SubjectScore> subjectScoreMap = new HashMap<>();
        for (SubjectScoreDetailDO detail : subjectScores) {
            SubjectScore subjectScore = new SubjectScore(
                detail.getOriginalScore(),
                detail.getAssignedScore(),
                detail.getGradeLevel(),
                detail.getSchoolRank(),
                detail.getClassRank()
            );
            subjectScoreMap.put(detail.getSubjectName(), subjectScore);
        }
        info.setSubjectScores(subjectScoreMap);
        
        return info;
    }

    @Override
    public List<StudentRankingInfo> getClassRankingList(Long examId, Long classId) {
        // 根据班级ID获取班级名称，然后查询该班级的所有学生
        List<ExamScoreDO> classScores = examScoreMapper.selectByExamIdAndClassId(examId, classId);
        
        return classScores.stream()
            .map(score -> getStudentRankingInfo(examId, score.getStudentId()))
            .filter(Objects::nonNull)
            .sorted(Comparator.comparing(StudentRankingInfo::getClassRank, 
                Comparator.nullsLast(Comparator.naturalOrder())))
            .collect(Collectors.toList());
    }

    @Override
    public List<StudentRankingInfo> getCombinationRankingList(Long examId, String subjectCombination) {
        List<ExamScoreDO> combinationScores = examScoreMapper
            .selectByExamIdAndSubjectCombination(examId, subjectCombination);
        
        return combinationScores.stream()
            .map(score -> getStudentRankingInfo(examId, score.getStudentId()))
            .filter(Objects::nonNull)
            .sorted(Comparator.comparing(StudentRankingInfo::getCombinationRank, 
                Comparator.nullsLast(Comparator.naturalOrder())))
            .collect(Collectors.toList());
    }

    @Override
    public List<SubjectRankingInfo> getSubjectRankingList(Long examId, String subjectName, String rankingType) {
        List<SubjectScoreDetailDO> subjectScores = subjectScoreDetailMapper
            .selectByExamIdAndSubject(examId, subjectName);
        
        return subjectScores.stream()
            .map(detail -> {
                SubjectRankingInfo info = new SubjectRankingInfo();
                info.setStudentId(detail.getStudentId());
                info.setSubjectName(detail.getSubjectName());
                info.setOriginalScore(detail.getOriginalScore());
                info.setAssignedScore(detail.getAssignedScore());
                info.setGradeLevel(detail.getGradeLevel());
                info.setSchoolRank(detail.getSchoolRank());
                info.setClassRank(detail.getClassRank());
                
                // 获取学生基本信息
                ExamScoreDO examScore = examScoreMapper.selectByExamIdAndStudentId(examId, detail.getStudentId());
                if (examScore != null) {
                    info.setStudentName(examScore.getStudentName());
                    info.setStudentNo(examScore.getStudentNo());
                    info.setClassName(examScore.getClassName());
                }
                
                return info;
            })
            .sorted((a, b) -> {
                Integer rankA = "class".equals(rankingType) ? a.getClassRank() : a.getSchoolRank();
                Integer rankB = "class".equals(rankingType) ? b.getClassRank() : b.getSchoolRank();
                return Comparator.comparing((Integer rank) -> rank, 
                    Comparator.nullsLast(Comparator.naturalOrder())).compare(rankA, rankB);
            })
            .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void recalculateStudentRanking(Long examId, Long studentId) {
        // 重新计算该学生的所有排名
        calculateAllRankings(examId);
    }

    @Override
    public RankingValidationResult validateRankingConsistency(Long examId) {
        List<String> errorMessages = new ArrayList<>();
        List<String> warningMessages = new ArrayList<>();
        Map<String, Integer> duplicateRanks = new HashMap<>();
        Map<String, Integer> missingRanks = new HashMap<>();
        
        // 验证总分排名的一致性
        List<ExamScoreDO> allScores = examScoreMapper.selectListByExamId(examId);
        
        // 检查校内排名
        validateRankingSequence(allScores, "school", errorMessages, duplicateRanks, missingRanks);
        
        // 按班级检查班级排名
        Map<String, List<ExamScoreDO>> scoresByClass = allScores.stream()
            .collect(Collectors.groupingBy(ExamScoreDO::getClassName));
        
        for (Map.Entry<String, List<ExamScoreDO>> entry : scoresByClass.entrySet()) {
            validateRankingSequence(entry.getValue(), "class_" + entry.getKey(), 
                errorMessages, duplicateRanks, missingRanks);
        }
        
        // 按选科组合检查组合排名
        Map<String, List<ExamScoreDO>> scoresByCombination = allScores.stream()
            .filter(score -> score.getSubjectCombination() != null)
            .collect(Collectors.groupingBy(ExamScoreDO::getSubjectCombination));
        
        for (Map.Entry<String, List<ExamScoreDO>> entry : scoresByCombination.entrySet()) {
            validateRankingSequence(entry.getValue(), "combination_" + entry.getKey(), 
                errorMessages, duplicateRanks, missingRanks);
        }
        
        boolean valid = errorMessages.isEmpty();
        return new RankingValidationResult(valid, errorMessages, warningMessages, 
            duplicateRanks, missingRanks);
    }
    
    /**
     * 验证排名序列的一致性
     */
    private void validateRankingSequence(List<ExamScoreDO> scores, String rankingType, 
                                       List<String> errorMessages, 
                                       Map<String, Integer> duplicateRanks,
                                       Map<String, Integer> missingRanks) {
        if (scores.isEmpty()) {
            return;
        }
        
        // 获取排名列表
        List<Integer> ranks = scores.stream()
            .map(score -> {
                switch (rankingType.split("_")[0]) {
                    case "school": return score.getSchoolRank();
                    case "class": return score.getClassRank();
                    case "combination": return score.getCombinationRank();
                    default: return null;
                }
            })
            .filter(Objects::nonNull)
            .sorted()
            .collect(Collectors.toList());
        
        if (ranks.isEmpty()) {
            return;
        }
        
        // 检查重复排名
        Set<Integer> uniqueRanks = new HashSet<>(ranks);
        if (uniqueRanks.size() != ranks.size()) {
            Map<Integer, Long> rankCounts = ranks.stream()
                .collect(Collectors.groupingBy(rank -> rank, Collectors.counting()));
            
            for (Map.Entry<Integer, Long> entry : rankCounts.entrySet()) {
                if (entry.getValue() > 1) {
                    duplicateRanks.put(rankingType + "_rank_" + entry.getKey(), 
                        entry.getValue().intValue());
                    errorMessages.add(String.format("%s 排名 %d 出现 %d 次重复", 
                        rankingType, entry.getKey(), entry.getValue()));
                }
            }
        }
        
        // 检查缺失排名
        int expectedMaxRank = ranks.size();
        for (int i = 1; i <= expectedMaxRank; i++) {
            if (!uniqueRanks.contains(i)) {
                missingRanks.put(rankingType + "_rank_" + i, 1);
                errorMessages.add(String.format("%s 缺失排名 %d", rankingType, i));
            }
        }
    }

}